package com.nt.train.annoreflect;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
 *  注解工厂处理器
 * @author hlf
 * @version 1.0
 * @date 2022/8/11 15:00
 */
public class AnnotationFactory {

    /**
     * 根据指定的Class对象,创建对应类的对象,
     * 同时读取类中的@Bean注解,根据注解信息,实现依赖注入
     * 该方法演示了注解信息获取与反射相关的方法
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T getBean(Class<T> clazz) {
        T obj = null;
        try {
            // 创建参数clazz代表的类的对象
            // 通过构造对象(Constructor)的静态方法newInstance()对象
            obj = clazz.getConstructor().newInstance();
            // 得到类中所有声明的方法 获得所有的方法描述类Method,
            Method[] methods = clazz.getDeclaredMethods();
            for (Method method : methods) {
                // Method 实现了AnnotationElement接口,该方法取到筛选作用
                Object implObject = getImplObject(method);
                if (implObject != null) {
                    // 调用方法,传入依赖的对象
                    method.invoke(obj, implObject);
                }
            }
            // 得到类中声明的所有的字段
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                // 只获取到标准有@NTBean注解的所有域
                Object implObject = getImplObject(field);
                if (implObject != null) {
                    // 设置值
                    field.setAccessible(Boolean.TRUE);
                    // 执行set方法及对应的值
                    field.set(obj, implObject);
                    field.setAccessible(Boolean.FALSE);
                }
            }
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            e.printStackTrace();
        }
        return obj;
    }

    /**
     * 使用辅助方法,根据Bean注解的元素的值创建对应的对象,
     * Field和Method类都实现了AnnotationElement接口
     * 该实现类只处理标记有@Bean注解的方法
     * @param element
     * @return
     * @throws NoSuchMethodException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    private static Object getImplObject(AnnotatedElement element)
            throws NoSuchMethodException,
            InstantiationException,
            IllegalAccessException,
            InvocationTargetException { // 必须声明这些异常,否则clazz.getDeclaredConstructor().newInstance(); 必需要方法参数
        if (element.isAnnotationPresent(NTBean.class)) { // 判断element注解实现类是否有Bean这个注解
            NTBean beanAnnotation = element.getDeclaredAnnotation(NTBean.class);
            Class<?> clazz = beanAnnotation.value();
            return clazz.getDeclaredConstructor().newInstance(); // 返回的是一个标注有@Bean注解的对象
        }
        return null;
    }
}